import json
from moviepy.editor import *
from moviepy.video.VideoClip import TextClip
from moviepy.video.io.ffmpeg_reader import ffmpeg_parse_infos
from utils import *
from tqdm import tqdm
import time

phone_resolution = (540, 960)


def resize_and_center_clip(clip):
    clip_aspect_ratio = clip.w / float(clip.h)
    frame_aspect_ratio = 480 / 240.0
    frame_width = 540
    frame_height = int(frame_width / frame_aspect_ratio)  # maintain same aspect ratio, adjust height accordingly

    if clip_aspect_ratio > frame_aspect_ratio:
        # adjust width to frame width, scale height maintaining aspect ratio
        new_clip = clip.resize(width=frame_width)
        if new_clip.h > frame_height:
            new_clip = new_clip.resize(height=frame_height)  # if height is too large, adjust
    else:
        # adjust height to frame height, scale width maintaining aspect ratio
        new_clip = clip.resize(height=frame_height)
        if new_clip.w > frame_width:
            new_clip = new_clip.resize(width=frame_width)  # if width is too large, adjust

    new_clip = new_clip.set_position('center')  # center the clip in frame
    return new_clip


def wrap_text(text, font_size, max_width):
    if text is None:
        return '未知'
    words = text.split(' ')
    lines = []
    current_line = []
    for word in words:
        current_line.append(word)
        clip = TextClip(' '.join(current_line), fontsize=font_size)
        if clip.w > max_width:
            current_line.pop()
            lines.append(' '.join(current_line))
            current_line = [word]
    lines.append(' '.join(current_line))
    return '\n'.join(lines)


def wrap_text_zh(text, font_size, max_width, english=False):
    connector = ''
    if english:
        connector = ' '
    if text is None:
        return '未知'
    if ' ' in text:
        words = text.split(' ')
    else:
        words = list(text)
    lines = []
    current_line = []
    for word in words:
        current_line.append(word)
        line_str = connector.join(current_line) if words is list(text) else connector.join(current_line)
        clip = TextClip(line_str, fontsize=font_size)
        if clip.w > max_width:
            current_line.pop()
            lines.append(connector.join(current_line) if words is list(text) else connector.join(current_line))
            current_line = [word]
    lines.append(connector.join(current_line) if words is list(text) else connector.join(current_line))
    return '\n'.join(lines)


def parse_meta(phrase):
    folder = concat_phrase(phrase)
    with open(f'{folder}/{folder}.json', 'r') as f:
        return json.load(f)


def get_title(metas, video_name):
    for meta in metas:
        vid = meta['link'].split('/')[-1]
        if vid == video_name:
            return meta['title']
    return '未知'


def is_broken_video(video_path):
    try:
        ffmpeg_parse_infos(video_path)
        return False
    except Exception:
        return True


def restore_phrase(phrase):
    clean_phrase = phrase.replace('-', ' ')
    return clean_phrase[0].upper() + clean_phrase[1:]


def render(phrase):
    video_source_path = check_video_folder(phrase)
    check_if_video_folder_has_stuff_int_it(phrase)
    background_image_path = './background.png'
    background_clip = ImageClip(background_image_path, duration=10).set_position('center').resize(phone_resolution)
    clips_paths = [file_name for file_name in os.listdir(video_source_path) if file_name.endswith('.mp4')]
    videos_list = []
    metas = parse_meta(phrase)
    print(f'found {len(clips_paths)} clips, processing...')
    textual_clips = []
    for clip_path in tqdm(clips_paths):
        full_clip_path = os.path.join(video_source_path, clip_path)
        if is_broken_video(full_clip_path):
            print(f'Error reading the video:{full_clip_path}')
            continue
        video_clip = VideoFileClip(full_clip_path)
        resized_clip = resize_and_center_clip(video_clip)
        title = get_title(metas, clip_path)
        title = wrap_text(title, 28, 450)
        text_clip = (TextClip(title, fontsize=28, color='white', align='center').set_duration(video_clip.duration))
        textual_clips.append(text_clip)
        videos_list.append(resized_clip)
    final_clip = concatenate_videoclips(videos_list, method='chain')
    final_video = CompositeVideoClip(
        [background_clip.set_duration(final_clip.duration)] + [final_clip.set_position("center")] + [
            background_clip.set_duration(final_clip.duration)])
    textual_clips_combined = concatenate_videoclips(textual_clips, method='chain')
    final_video = CompositeVideoClip(
        [final_video.set_position('center')] + [textual_clips_combined.set_position(('center', 675))])
    print('writing final video...')
    video_name = f'{phrase}-final.mp4'
    title_text = wrap_text(restore_phrase(phrase), 36, 480)
    title_clip = TextClip(title_text, fontsize=36, color='yellow', align='center').set_duration(final_video.duration)
    with open(f'{video_source_path}/translate.txt', 'r') as f:
        translations = f.read().split('\n')
    trans_total = ''
    for i in range(1, len(translations) + 1):
        trans_total += wrap_text_zh(f'{translations[i - 1]}\n', 25, 380)
    final_video = CompositeVideoClip([final_video, title_clip.set_position(('center', 50))])
    final_video = CompositeVideoClip([final_video, TextClip(trans_total, fontsize=25, color='white', align='West',
                                                            font='simhei.ttf').set_duration(
        final_video.duration).set_position((25, 100))])
    final_video.write_videofile(video_name, fps=24, codec='libx264', threads=20, ffmpeg_params=["-c:v", "h264_nvenc"])


start = time.time()
render(get_phrase())
duration = time.time() - start
print(f'duration: {round(duration, 2)} seconds')
